package com.bestcem.xm.user.grpc.client;

import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.bp.pay.grpc.v1.enums.OrderTypeEnum;
import com.bestcem.bp.pay.grpc.v1.services.*;
import com.bestcem.xm.common.core.constant.GrpcClientNames;
import com.bestcem.xm.common.core.sign.grpc.core.GrpcTemplate;
import com.bestcem.xm.user.grpc.client.convert.OrderGrpcConvert;
import com.bestcem.xm.user.grpc.client.dto.MiniProgramOrderDTO;
import com.bestcem.xm.user.grpc.client.dto.OrderDTO;
import com.bestcem.xm.user.service.dto.order.OnlineOrderDTO;
import com.bestcem.xm.user.service.dto.order.PaySignatureDTO;
import com.bestcem.xm.user.service.dto.order.WalletOrderDTO;
import com.bestcem.xm.user.service.dto.order.WeChatOrderDTO;
import com.bestcem.xm.user.service.dto.user.OrganizationDTO;
import com.bestcem.xm.user.service.dto.user.UserDTO;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 支付服务相关grpc接口
 *
 * @author panyun <yun.pan@idiaoyan.com>
 * @version v1.0
 * @date 2022/5/7 12:23
 */
@Slf4j
@Service
public class UserPaymentGrpcService {

    @GrpcClient(GrpcClientNames.PAY)
    private PaymentServiceGrpc.PaymentServiceBlockingStub stub;

    @Resource
    private OrderGrpcConvert orderGrpcConvert;

    @Resource
    private GrpcTemplate grpcTemplate;

    /**
     * 创建线下支付订单
     *
     * @param type        订单类型
     * @param subject     订单简要描述信息
     * @param description 订单详细描述信息
     * @param userDTO     付款操作执行人标识
     * @param org         支付企业
     * @param totalAmount 订单金额
     * @param extra       订单附加信息
     * @return java.lang.String
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/5/7 14:01
     */
    public String createOfflineOrder(int type, String subject, String description, UserDTO userDTO, OrganizationDTO org, int totalAmount, String extra) {
        if (log.isInfoEnabled()) {
            log.info("创建线下支付订单：subject:{} orgId:{} totalMount:{}", subject, org.getOrgId(), totalAmount);
        }
        CreateOfflineOrderRequest.Builder builder = CreateOfflineOrderRequest.newBuilder();
        Order.Builder order = Order.newBuilder();
        order.setWalletId(org.getCorpWallet())
                .setType(OrderTypeEnum.OrderType.forNumber(type))
                .setSubject(subject)
                .setDescription(description)
                .setPayerUserId(userDTO.getUserId())
                .setPayerUserName(userDTO.getUserName())
                .setPayerOrgId(org.getOrgId())
                .setPayerOrgCode(org.getCode())
                .setPayerOrgName(org.getName())
                .setTotalAmount(totalAmount)
                .setExtra(extra);
        builder.setOrder(order);
        CreateOfflineOrderRequest request = builder.build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        CreateOfflineOrderResponse offlineOrder = stub.createOfflineOrder(request);
        if (Code.ERROR_VALUE == offlineOrder.getStatus().getCodeValue()) {
            log.error("创建线下支付订单失败 subject:{}", subject);
            return null;
        }
        return offlineOrder.getOrderNo();
    }

    /**
     * 获取订单状态，用于轮询订单
     *
     * @param orderNo 订单号
     * @return com.bestcem.xm.user.grpc.client.dto.OrderInfoDTO
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/5/7 16:05
     */
    public OrderDTO getOrderStatus(String orderNo) {
        if (log.isInfoEnabled()) {
            log.info("线下支付订单, 用户已完成支付请求：orderNo:{}", orderNo);
        }
        GetOrderStatusRequest request = GetOrderStatusRequest.newBuilder().setOrderNo(orderNo).build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        GetOrderStatusResponse response = stub.getOrderStatus(request);
        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("线下支付订单, 用户已完成支付请求失败：orderNo:{}", orderNo);
            return null;
        }
        OrderDTO orderDTO = orderGrpcConvert.order2OrderDTO(response.getOrder());
        String totalMount = orderDTO.getTotalAmount().toString();
        String substring = totalMount.substring(0, totalMount.length() - 2);
        orderDTO.setTotalAmount(Integer.valueOf(substring));
        return orderDTO;
    }

    /**
     * 线下支付订单, 用户点击已完成支付
     *
     * @param orderNo 订单号
     * @return java.lang.String
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/5/7 19:04
     */
    public String confirmOfflinePay(String orderNo) {
        if (log.isInfoEnabled()) {
            log.info("线下支付订单, 用户点击已完成支付请求：orderNo:{}", orderNo);
        }
        ConfirmOfflinePayRequest request = ConfirmOfflinePayRequest.newBuilder().setOrderNo(orderNo).build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        ConfirmOfflinePayResponse response = stub.confirmOfflinePay(request);
        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("线下支付订单, 用户点击已完成支付请求失败：orderNo:{}", orderNo);
            return null;
        }
        return response.getOrderNo();
    }


    /**
     * 创建小程序支付订单
     *
     * @param orderDTO
     * @return java.lang.Object
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/06 17:50
     */
    public WeChatOrderDTO createMiniProgramOrder(MiniProgramOrderDTO orderDTO) {
        CreateMiniProgramOrderRequest.Builder builder = CreateMiniProgramOrderRequest.newBuilder();
        Order order = orderGrpcConvert.walletOrderDTO2Order(orderDTO.getOrder());
        builder.setOrder(order);
        builder.setOpenId(orderDTO.getOpenid());
        CreateMiniProgramOrderRequest request = builder.build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        CreateMiniProgramOrderResponse response = stub.createMiniProgramOrder(request);
        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("创建小程序支付订单异常: orderDTO:{} response: {}", orderDTO, response.getStatus().getMessage());
            return null;
        }
        return response2WechatOrderDTO(response);
    }


    /**
     * 创建在线支付订单
     *
     * @param orderDTO
     * @return com.bestcem.xm.user.service.dto.order.OnlineOrderDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/06 23:17
     */
    public OnlineOrderDTO createOnlineOrder(WalletOrderDTO orderDTO) {
        if (log.isInfoEnabled()) {
            log.info("[USER]创建在线支付订单请求 orderDTO:{}", orderDTO.toString());
        }

        OnlineOrderDTO onlineOrderDTO = new OnlineOrderDTO();
        CreateOnlineOrderRequest.Builder builder = CreateOnlineOrderRequest.newBuilder();
        Order order = orderGrpcConvert.walletOrderDTO2Order(orderDTO);
        builder.setOrder(order);
        CreateOnlineOrderRequest request = builder.build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        CreateOnlineOrderResponse response = stub.createOnlineOrder(request);

        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("创建在线支付订单异常: orderDTO:{} response: {}", orderDTO, response.getStatus().getMessage());
            return null;
        }
        onlineOrderDTO.setOrderNo(response.getOrderNo());
        onlineOrderDTO.setCodeUrl(response.getCodeUrl());
        if (log.isInfoEnabled()) {
            log.info("[USER]创建在线支付订单响应。onlineOrderDTO:{}", onlineOrderDTO.toString());
        }
        return onlineOrderDTO;
    }

    /**
     * 获取订单状态，用于轮询订单
     *
     * @param orderNo
     * @return com.bestcem.xm.user.grpc.client.dto.OrderDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/07 11:13
     */
    public OrderDTO getOrderStatus2(String orderNo) {
        GetOrderStatusRequest.Builder builder = GetOrderStatusRequest.newBuilder();
        builder.setOrderNo(orderNo);
        GetOrderStatusRequest request = builder.build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        GetOrderStatusResponse response = stub.getOrderStatus(request);
        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("获取订单状态异常: orderNo:{} response: {}", orderNo, response.getStatus().getMessage());
            return null;
        }
        return orderGrpcConvert.order2OrderDTO(response.getOrder());
    }


    /**
     * 完成订单
     *
     * @param orderDTO
     * @return java.lang.String
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/09 14:00
     */
    public String completeOrder(OrderDTO orderDTO) {
        CompleteOrderRequest.Builder builder = CompleteOrderRequest.newBuilder();
        Order order = orderGrpcConvert.orderDTO2Order(orderDTO);
        builder.setOrder(order);
        CompleteOrderRequest request = builder.build();
        // 加签并请求
        grpcTemplate.addSign(request, GrpcTemplate.SEVER_CODE_PAY);
        CompleteOrderResponse response = stub.completeOrder(request);
        if (Code.ERROR_VALUE == response.getStatus().getCodeValue()) {
            log.error("完成订单异常: orderDTO:{} response: {}", orderDTO, response.getStatus().getMessage());
            return null;
        }
        return response.getOrderNo();
    }

    private WeChatOrderDTO response2WechatOrderDTO(CreateMiniProgramOrderResponse response) {
        if (response == null) {
            return null;
        }

        WeChatOrderDTO weChatOrderDTO = new WeChatOrderDTO();
        PaySignatureDTO paySignatureDTO = new PaySignatureDTO();

        if (response.getOrderNo() != null) {
            weChatOrderDTO.setOrderId(response.getOrderNo());
        }
        if (response.getAppId() != null) {
            paySignatureDTO.setAppId(response.getAppId());
        }
        if (response.getTimestamp() != null) {
            paySignatureDTO.setTimestamp(response.getTimestamp());
        }

        if (response.getNonceStr() != null) {
            paySignatureDTO.setNonceStr(response.getNonceStr());
        }

        if (response.getPackage() != null) {
            paySignatureDTO.setPackageStr(response.getPackage());
        }

        if (response.getSignType() != null) {
            paySignatureDTO.setSignType(response.getSignType());
        }

        if (response.getPaySign() != null) {
            paySignatureDTO.setPaySign(response.getPaySign());
        }
        weChatOrderDTO.setPaySignatureDTO(paySignatureDTO);
        return weChatOrderDTO;
    }
}
